﻿@page "/CanvasDraw"

@using System.Diagnostics.CodeAnalysis
@using System.Drawing;
@using System.Reflection
@using BlazorSample.Extensions

@inject IJSRuntime jsRuntime

<ErrorBoundary>

</ErrorBoundary>
<style>
    #imageContainer {
        position: relative;
        width: 600px; /* 根据需要设置 */
        height: 400px; /* 根据需要设置 */
        overflow: hidden;
    }

        #imageContainer img {
            display: block;
        }

        #imageContainer svg {
            position: absolute;
            top: 0;
            left: 0;
        }

    #myCanvas {
        z-index: 1; /* 确保 canvas 在 img 之上 */
        position: absolute; /* 或者 relative, fixed, sticky */
    }

    .text-css {
        transform: rotate(90deg);
    }
</style>

<h3>CanvasDraw</h3>

<input value="@PointJson" style="width: 600px; " />
<input @bind-value="@Width" style="width: 120px; " />
<input @bind-value="@Height" style="width: 120px; " />
<input @bind-value="@Angle" style="width: 120px; " />

 <RadzenButton Text="Refresh" Click="@ChangeDropDownClick"></RadzenButton> 
<RadzenDropDown Value=@SelectDrawType DisabledProperty=@nameof(DrawTypeDropDownDto.Disabled) Data=@DrawTypeDropDownList TValue=DrawType ValueChanged="@DrawTypeValueChanged" TextProperty=@nameof(DrawTypeDropDownDto.Name) ValueProperty=@nameof(DrawTypeDropDownDto.Value) Style="width:100%; display: block; max-width: 200px;" />

<div>
    <select @onchange=@DrawTypeValueChanged width="100px">
        @foreach (var item in DrawTypeDropDownList)
        {
            <option value="@item.Value">@item.Name</option>
        }
    </select>
</div>

<Button Text="Update Width/Height" OnClick="UpdateClick" />
<Button Text="Draw" OnClick="DrawClick" />
<Button Text="SelectDraw" OnClick="SelectDrawClick" />
<Button Text="ClearDraw" OnClick="ClearDrawClick" />
<Button Text="DeleteDraw" OnClick="DeleteDrawClick" />
<Button Text="GetAllLine" OnClick="GetAllLineClick" />
<Button Text="Update Angle" OnClick="UpdateAngleClick" />

<RadzenRow AlignItems="AlignItems.Center" Gap="0">
    <div id="divCanvas" style="position: relative; width: 600px; height: 400px;">
        <canvas id="myCanvas" width="@Width" height="@Height">
        </canvas>
        <img id="myImage" src="@imageUrl" width="@Width" height="@Height" style="position: absolute; top: 0; left: 0;" />
    </div>
    <p class="text-css">右边</p>
</RadzenRow>
<RadzenRow AlignItems="AlignItems.Center" Gap="0">
    <p>下边</p>
</RadzenRow>


<RadzenDataGrid EditMode="@editMode" @ref=grid TItem="RectangleInfo" AllowPaging="false" PageSize="5" AllowSorting="false"
                Data="@rectangleData" RowUpdate="@OnUpdateRow" Sort="@(args => Reset())" Page="@(args => Reset())" Filter="@(args => Reset())"
                ColumnWidth="200px" AllowColumnResize="true" SelectionMode="DataGridSelectionMode.Single" @bind-Value=@selectedRectangles RowSelect="RowSelectClick" FilterPopupRenderMode="PopupRenderMode.OnDemand" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive">
    <Columns>
        <RadzenDataGridColumn TItem="RectangleInfo" Property=@nameof(RectangleInfo.Name) Title=@nameof(RectangleInfo.Name) Width="120px" IsInEditMode="@IsEditing">
            <Template Context="data">
                <RadzenText Text="@(data.Name)" />
            </Template>
            <EditTemplate Context="data">
                <RadzenTextBox @bind-Value="data.Name" Style="width:120px; display: block" Name=@nameof(RectangleInfo.Name) />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn Width="40px" TItem="RectangleInfo" Property=@nameof(RectangleInfo.Show) Title=@nameof(RectangleInfo.Show) IsInEditMode="@IsEditing">
            <Template Context="data">
                <RadzenCheckBox Value="@data.Show" Name="Show" />
            </Template>
            <EditTemplate Context="data">
                <RadzenCheckBox @bind-Value=data.Show Name="Show" />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn TItem="RectangleInfo" Property=@nameof(RectangleInfo.StartX) Title=@nameof(RectangleInfo.StartX) IsInEditMode="@IsEditing">
            <Template Context="data">
                <RadzenText Text="@(data.StartX.ToString())" />
            </Template>
            <EditTemplate Context="data">
                <RadzenNumeric @bind-Value=data.StartX Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "Select freight" }})" />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn TItem="RectangleInfo" Property=@nameof(RectangleInfo.StartY) Title=@nameof(RectangleInfo.StartY) IsInEditMode="@IsEditing">
            <Template Context="data">
                <RadzenText Text="@(data.StartY.ToString())" />
            </Template>
            <EditTemplate Context="data">
                <RadzenNumeric @bind-Value="data.StartY" Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "Select freight" }})" />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn TItem="RectangleInfo" Property=@nameof(RectangleInfo.EndX) Title=@nameof(RectangleInfo.EndX) IsInEditMode="@IsEditing">
            <Template Context="data">
                <RadzenText Text="@(data.EndX.ToString())" />
            </Template>
            <EditTemplate Context="data">
                <RadzenNumeric @bind-Value="data.EndX" Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "Select freight" }})" />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn TItem="RectangleInfo" Property=@nameof(RectangleInfo.EndY) Title=@nameof(RectangleInfo.EndY) IsInEditMode="@IsEditing">
            <Template Context="data">
                <RadzenText Text="@(data.EndY.ToString())" />
            </Template>
            <EditTemplate Context="data">
                <RadzenNumeric @bind-Value="data.EndY" Style="width:100%" InputAttributes="@(new Dictionary<string,object>(){ { "aria-label", "Select freight" }})" />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn TItem="RectangleInfo" Property=@nameof(RectangleInfo.BaseLine) Title=@nameof(RectangleInfo.BaseLine) IsInEditMode="@IsEditing" Visible="@BaseLineVisible">
            <Template Context="data">
                <RadzenCheckBox Value="@data.BaseLine" Name="BaseLine" />
            </Template>
            <EditTemplate Context="data">
                <RadzenCheckBox @bind-Value=data.BaseLine Name="BaseLine" />
            </EditTemplate>
        </RadzenDataGridColumn>

        <RadzenDataGridColumn Width="80px" TItem="RectangleInfo" Filterable="false" Sortable="false" TextAlign="Radzen.TextAlign.Center" Frozen="true" FrozenPosition="FrozenColumnPosition.Right">
            <Template Context="data">
                <RadzenButton Icon="edit" ButtonStyle="Radzen.ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@(args => EditRow(data))" @onclick:stopPropagation="true">
                </RadzenButton>
                <RadzenButton ButtonStyle="Radzen.ButtonStyle.Danger" Icon="delete" Variant="Variant.Flat" Shade="Shade.Lighter" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@(args => DeleteRow(data))" @onclick:stopPropagation="true">
                </RadzenButton>
            </Template>
            <EditTemplate Context="data">
                <RadzenButton Icon="check" ButtonStyle="Radzen.ButtonStyle.Success" Variant="Variant.Flat" Size="ButtonSize.Medium" Click="@((args) => SaveRow(data))" aria-label="Save">
                </RadzenButton>
                <RadzenButton Icon="close" ButtonStyle="Radzen.ButtonStyle.Light" Variant="Variant.Flat" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@((args) => CancelEdit(data))" aria-label="Cancel">
                </RadzenButton>
                <RadzenButton ButtonStyle="Radzen.ButtonStyle.Danger" Icon="delete" Variant="Variant.Flat" Shade="Shade.Lighter" Size="ButtonSize.Medium" class="my-1 ms-1" Click="@(args => DeleteRow(data))" aria-label="Delete">
                </RadzenButton>
            </EditTemplate>
        </RadzenDataGridColumn>

    </Columns>
</RadzenDataGrid>

<RadzenCard Variant="Variant.Outlined">
    <RadzenStack Orientation="Radzen.Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="1.5rem;" Wrap="FlexWrap.Wrap">
        <RadzenButton Click="@ClearSelection" Text="Clear Selection" />
        @if (selectedRectangles?.Any() == true)
        {
            <div>
                Selected Employee: @selectedRectangles[0].Name @selectedRectangles[0].StartX @selectedRectangles[0].StartY
            </div>
        }
    </RadzenStack>
</RadzenCard>

<Button Text="Add" OnClick="AddRowClick" />
<Button Text="BaseLine Visible" OnClick="BaseLineVisibleClick" />
<script src="./CanvasDraw.js"></script>

@code {

    private string imageUrl = "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?0";

    private bool isMouseDown = false;

    private System.Drawing.Point? startPoint;

    private System.Drawing.Point? endPoint;

    private string PointJson = "123";

    private int Width { get; set; } = 600;

    private int Height { get; set; } = 400;

    private int Angle { get; set; } = 0;

    private DotNetObjectReference<CanvasDraw> dotNetObjectReference;

    private bool isCanDraw = false;

    private bool isSelectDraw = false;

    public DrawType SelectDrawType { get; set; } = DrawType.Line;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await jsRuntime.InvokeVoidAsync("import", "./CanvasDraw.js");
        await jsRuntime.InvokeVoidAsync("import", "./Resizer.js");
        if (firstRender)
        {
            await jsRuntime.InvokeVoidAsync("import", "./_content/Radzen.Blazor/Radzen.Blazor.js");

            await jsRuntime.InvokeVoidAsync("eval", @"
    function resizeImage(elementId, width, height) {
    var img = document.getElementById(elementId);
    if (img) {
    img.style.width = width + 'px';
    img.style.height = height + 'px';
    }
    }
    ");
        }
    }

    protected override async Task OnInitializedAsync()
    {
        await jsRuntime.InvokeVoidAsync("import", "./_content/Radzen.Blazor/Radzen.Blazor.js");
        selectedRectangles = new List<RectangleInfo>();
        InitDrawTypeDropDownList();
        await base.OnInitializedAsync();
    }

    private RectangleInfo? SelectRect;

    [JSInvokable("MouseSelect")]
    public async Task MouseSelect(RectangleInfo line)
    {
        SelectRect = line;
        if (SelectRect != null)
        {
            isSelectDraw = true;
        }
        PrintPoint();
        rectangleData = await jsRuntime.InvokeAsync<List<RectangleInfo>>("GetAllRectangle");
        rectangleData.ForEach(s =>
        {
            CalPointRatio(s, Width, Height);
        });
        await grid.Reload();
        base.StateHasChanged();

        await SetSelectRectangle(line);
    }

    [JSInvokable("MouseDown")]
    public async Task MouseDown(int x, int y)
    {
        startPoint = new System.Drawing.Point(x, y);
    }

    [JSInvokable("MouseMove")]

    public async Task MouseMove(int x, int y)
    {
        endPoint = new System.Drawing.Point(x, y);
        var line = new RectangleInfo
            {
                StartY = startPoint.Value.Y,
                EndX = endPoint.Value.X,
                EndY = endPoint.Value.Y,
                StartX = startPoint.Value.X,
            };
        PointJson = System.Text.Json.JsonSerializer.Serialize(line);
        base.StateHasChanged();
    }

    private void PrintPoint()
    {
        PointJson = System.Text.Json.JsonSerializer.Serialize(SelectRect);
        base.StateHasChanged();
    }

    private async Task DrawClick()
    {
        isCanDraw = true;
        dotNetObjectReference = DotNetObjectReference.Create(this);
        await jsRuntime.InvokeVoidAsync("initCanvas", dotNetObjectReference, (int)SelectDrawType, isCanDraw, false);
    }

    private async Task ClearDrawClick()
    {
        isCanDraw = false;
        await jsRuntime.InvokeVoidAsync("clearCanvas");
    }

    private async Task SelectDrawClick()
    {
        await jsRuntime.InvokeVoidAsync("RectangleCanSelect", true);
    }

    private async Task DeleteDrawClick()
    {
        isCanDraw = false;
        await jsRuntime.InvokeVoidAsync("deleteDraw", SelectRect?.Id);
    }

    private async Task GetAllLineClick()
    {
        var lines = await jsRuntime.InvokeAsync<List<RectangleInfo>>("GetAllRectangle");
    }

    private async Task UpdateAngleClick()
    {
        await jsRuntime.InvokeVoidAsync("RotateLine", Angle);
    }


    private async Task UpdateClick()
    {
        await jsRuntime.InvokeVoidAsync("resizeImage", "divCanvas", Width, Height);
    }

    public List<DrawTypeDropDownDto> DrawTypeDropDownList = new List<DrawTypeDropDownDto>();

    private void InitDrawTypeDropDownList()
    {
        foreach (DrawType value in Enum.GetValues(typeof(DrawType)))
        {
            DrawTypeDropDownList.Add(new DrawTypeDropDownDto
                {
                    Name = value.ToString(),
                    Value = (int)value,
                    Disabled = value == DrawType.Line,
                });
        }
    }

    public async Task DrawTypeValueChanged(DrawType data)
    {
        this.SelectDrawType = data;
    }

    public async Task DrawTypeValueChanged(ChangeEventArgs args)
    {
        var selectValue = (args == null || args.Value == null) ? "0" : args.Value.ToString();
        SelectDrawType = (DrawType)int.Parse(selectValue.ToString());
        await jsRuntime.InvokeVoidAsync("initCanvas", dotNetObjectReference, (int)SelectDrawType, isCanDraw, false);
        await jsRuntime.InvokeVoidAsync("clearCanvas");

    }

    #region Line DataGrid

    public IList<RectangleInfo> selectedRectangles;
    public List<RectangleInfo> rectangleData = new List<RectangleInfo>();
    List<RectangleInfo> dataToUpdate = new List<RectangleInfo>();
    DataGridEditMode editMode = DataGridEditMode.Single;
    public RadzenDataGrid<RectangleInfo> grid;
    public string columnEditing;

    public bool BaseLineVisible = true;

    public bool IsEditing(string columnName, RectangleInfo data)
    {
        return columnEditing == columnName && dataToUpdate.Contains(data);
    }

    public void Reset(RectangleInfo data = null)
    {
        if (data != null)
        {
            dataToUpdate.Remove(data);
        }
        else
        {
            dataToUpdate.Clear();
        }
    }

    public async Task EditRow(RectangleInfo data)
    {
        Reset();

        dataToUpdate.Add(data);
        await grid.EditRow(data);
    }

    public void OnUpdateRow(RectangleInfo data)
    {
        Reset(data);
    }

    public async Task DeleteRow(RectangleInfo data)
    {
        Reset(data);
        if (rectangleData.Contains(data))
        {
            rectangleData.Remove(data);
            await grid.Reload();
        }
        else
        {
            grid.CancelEditRow(data);
            await grid.Reload();
        }
        await jsRuntime.InvokeVoidAsync("deleteDraw", data.Id);

        if (rectangleData.Count > 0)
        {
            await SetSelectRectangle(rectangleData.FirstOrDefault());
        }
    }

    async Task SaveRow(RectangleInfo data)
    {
        await grid.UpdateRow(data);
        var poiOtherData = rectangleData.FindAll(s => !s.Equals(data)).ToList();
        poiOtherData.ForEach(s => s.BaseLine = !data.BaseLine);

        await jsRuntime.InvokeVoidAsync("SaveRectangle", data);

        await SetSelectRectangle(data);
    }

    void CancelEdit(RectangleInfo data)
    {
        Reset(data);

        grid.CancelEditRow(data);
    }

    public async Task AddRowClick()
    {
        var currentIndex = rectangleData.Any() ? (rectangleData.Max(s => s.Index) + 1) : 1;
        string name = "";
        if (this.SelectDrawType == DrawType.Line)
        {
            name = $"Line{currentIndex}";
        }
        else
        {
            name = $"RZ{currentIndex}";
        }

        var insert = new RectangleInfo
            {
                Id = Guid.NewGuid().ToString(),
                Name = name,
                BaseLine = false,
                IsSelected = true,
                Show = true,
                StartX = (Width * 0.4).DoubleAccuracy("2"),
                StartY = (Height * 0.4).DoubleAccuracy("2"),
                EndX = (Width * 0.6).DoubleAccuracy("2"),
                EndY = (Height * 0.6).DoubleAccuracy("2"),
                Index = currentIndex,
            };
        rectangleData.Add(insert);
        await grid.Reload();

        await jsRuntime.InvokeVoidAsync("SaveRectangle", insert);

        await SetSelectRectangle(insert);
    }

    public async Task RowSelectClick(RectangleInfo data)
    {
        await SetSelectRectangle(data, false);
    }

    private async Task SetSelectRectangle(RectangleInfo selectData, bool isTriggerSelect = true)
    {
        selectedRectangles = null;
        selectedRectangles = new List<RectangleInfo>();
        if (selectData != null)
        {
            selectData.IsSelected = true;
            selectedRectangles.Add(selectData);
            if (isTriggerSelect)
                await grid.SelectRow(rectangleData.FirstOrDefault(s => s.Id == selectData.Id));
        }
        await jsRuntime.InvokeVoidAsync("SaveRectangle", selectData);
    }

    void ClearSelection()
    {
        selectedRectangles = null;
    }

    public void BaseLineVisibleClick()
    {
        this.BaseLineVisible = !BaseLineVisible;
    }

    private void CalPointRatio(RectangleInfo data, double CanvasWidth, double CanvasHeight)
    {
        data.StartRatioX = (data.StartX / CanvasWidth).DoubleAccuracy("2");
        data.StartRatioY = (data.StartY / CanvasHeight).DoubleAccuracy("2");
        data.EndRatioX = (data.EndX / CanvasWidth).DoubleAccuracy("2");
        data.EndRatioY = (data.EndY / CanvasHeight).DoubleAccuracy("2");

        data.OffsetRatioX = ((data.StartRatioX + data.EndRatioX) / 2).DoubleAccuracy("2");
        data.OffsetRatioY = ((data.StartRatioY + data.EndRatioY) / 2).DoubleAccuracy("2");
        data.SizeRatioX = ((data.EndRatioX - data.StartRatioX)).DoubleAccuracy("2");
        data.SizeRatioX = ((data.EndRatioY - data.StartRatioY)).DoubleAccuracy("2");
    }

    #endregion

    public async Task ChangeDropDownClick(MouseEventArgs args)
    {
        this.SelectDrawType = DrawType.Region;
    }
}
